package Serveur;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ArrayList;
import java.util.GregorianCalendar;

import Both.*;

/**
 * Classe Serialization
 * 
 * Cette classe possèdent toutes les fonctions nécessaires a la serialisation
 * des données de l'application.
 * 
 * @author Jeremie Blond, Joris Harnetiaux, Mourade Assou, Nolan Potier
 * 
 */
public class Serialization {
    private static final String FICHIER_LISTE_TRANSPORT = "listeTransport.txt";
    private static final String FICHIER_LISTE_TRAJET = "listeTrajet.txt";
    private static final String FICHIER_LISTE_RESERVATION = "listeReservation.txt";
    private static final String FICHIER_LISTE_PASSAGER = "listePassager.txt";
    private static final String BIN_LISTE_TRANSPORT = "Transports.dat";
    private static final String BIN_LISTE_TRAJET = "Trajet.dat";
    private static final String BIN_LISTE_PASSAGER = "Passagers.dat";
    private RandomAccessFile fichierTransport;
    private RandomAccessFile fichierTrajet;
    private RandomAccessFile fichierReservation;
    private RandomAccessFile fichierPassager;

    public static final String CAR_SPACE = "/";
    public static final String CAR_REPLACE = "_";

    public Serialization() {
        initialisation();
    }

    /**
     * supprimer les fichiers
     * 
     * @param return
     */
    public void sup() {
        File monFichier = new File(FICHIER_LISTE_TRANSPORT);
        if (monFichier.exists()) {
            monFichier.delete();
        }
        File monFichier2 = new File(FICHIER_LISTE_TRAJET);
        if (monFichier2.exists()) {
            monFichier2.delete();
        }
        File monFichier3 = new File(FICHIER_LISTE_RESERVATION);
        if (!monFichier3.exists()) {
            monFichier3.delete();
        }
        File monFichier4 = new File(FICHIER_LISTE_PASSAGER);
        if (!monFichier4.exists()) {
            monFichier4.delete();
        }
        File monFichier5 = new File(BIN_LISTE_PASSAGER);
        if (!monFichier5.exists()) {
            monFichier5.delete();
        }
    }

    /**
     * initialise les lectures/ecritures fichiers
     * 
     * @param return
     */
    public void initialisation() {
        try {
            fichierTransport = new RandomAccessFile(FICHIER_LISTE_TRANSPORT,
                    "rw");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            System.out.println("Impossible d'ouvrir le fichier "
                    + FICHIER_LISTE_TRANSPORT);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            fichierTrajet = new RandomAccessFile(FICHIER_LISTE_TRAJET, "rw");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            System.out.println("Impossible d'ouvrir le fichier "
                    + FICHIER_LISTE_TRAJET);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            fichierReservation = new RandomAccessFile(
                    FICHIER_LISTE_RESERVATION, "rw");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            System.out.println("Impossible d'ouvrir le fichier "
                    + FICHIER_LISTE_RESERVATION);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            fichierPassager = new RandomAccessFile(FICHIER_LISTE_PASSAGER, "rw");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            System.out.println("Impossible d'ouvrir le fichier "
                    + FICHIER_LISTE_PASSAGER);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * ferme les fichiers et appel les methodes pour sauvegarder les donnees
     * 
     * @param ListeTransport
     * @param ListeTrajet
     * @param ListeReservation
     *            return
     */
    public void close(ArrayList<Transport> ListeTransport,
            ArrayList<Trajet> ListeTrajet,
            ArrayList<Reservation> ListeReservation,
            ArrayList<Passager> ListePassager) {
        sup();
        initialisation();
        // on ecrit la liste des transport, trajet, reservation et on ferme les
        // fichiers
        serializeListe(ListeTransport, ListeTrajet, ListeReservation,
                ListePassager);
        try {
            fichierTransport.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fichierTrajet.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fichierReservation.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fichierPassager.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * ecrit un transport en bon format pour etre sauvegarde
     * 
     * @param Transport
     *            t return String
     */
    private String ecrireTransport(Transport t) {
        return (t.getType().name() + CAR_SPACE + t.getNumTrans() + CAR_SPACE + t
                .getCapacite());
    }

    /**
     * ecrit un trajet en bon format pour etre sauvegarde
     * 
     * @param Trajet
     *            t return String
     */
    private String ecrireTrajet(Trajet t) {
        return (t.getVilleDepart().getVille() + CAR_SPACE
                + t.getVilleArrive().getVille() + CAR_SPACE
                + getFormatedDate(t.getDateDepart().getTime()) + CAR_SPACE
                + getFormatedDate(t.getDateArrive().getTime()) + CAR_SPACE + t
                .getDistance());
    }

    /**
     * ecrit un passager en bon format pour etre sauvegarde
     * 
     * @param Trajet
     *            t return String
     */
    private String ecrirePassager(Passager p) {
        String retour = p.getCodeClient() + CAR_SPACE + p.getLogin()
                + CAR_SPACE + p.getMdp() + CAR_SPACE + p.getNom() + CAR_SPACE
                + p.getPrenom() + CAR_SPACE + p.getProfil().name() + CAR_SPACE
                + getFormatedDate(p.getDateDeNaissance().getTime()) + CAR_SPACE;
        for (Billet b : p.getBilletsReserves()) {
            retour += ecrireBillet(b);
        }

        return retour;

    }

    /**
     * ecrit un passager en bon format pour etre sauvegarde
     * 
     * @param Trajet
     *            t return String
     */
    private String ecrireBillet(Billet b) {
        String retour = b.getIdBillet() + CAR_SPACE + b.getProfil().name()
                + CAR_SPACE + b.getPrix() + CAR_SPACE
                + b.getTypeBillet().name() + CAR_SPACE;
        for (String s : b.getServices().keySet()) {
            retour += s + CAR_SPACE + b.getServices().get(s) + CAR_SPACE;
        }

        for (Trajet t : b.getTrajets()) {
            retour += ecrireTrajet(t) + CAR_SPACE;
        }

        return retour;
    }

    /**
     * sauvegarde tout les transports/trajets/reservations dans les fichiers
     * 
     * @param ListeTransport
     * @param ListeTrajet
     * @param ListeReservation
     * @return
     */
    public void serializeListe(ArrayList<Transport> ListeTransport,
            ArrayList<Trajet> ListeTrajet,
            ArrayList<Reservation> ListeReservation,
            ArrayList<Passager> ListePassager) {
        // on ecrit la liste des transports:
        // pour chaque transport on ecrit
        // nomTransport/descriptionTransport/capacitéTransport
        try {
            for (int i = 0; i < ListeTransport.size(); i++) {
                fichierTransport.writeBytes(ecrireTransport(ListeTransport
                        .get(i))
                        + "\n");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            for (int i = 0; i < ListeTrajet.size(); i++) {
                fichierTrajet.writeBytes(ecrireTrajet(ListeTrajet.get(i))
                        + CAR_SPACE
                        + ecrireTransport(ListeTrajet.get(i).getTransport())
                        + "\n");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            for (int i = 0; i < ListeReservation.size(); i++) {
                fichierReservation.writeBytes(ecrireTrajet(ListeReservation
                        .get(i).getTrajet())
                        + CAR_SPACE
                        + ListeReservation.get(i).getNbPersonne()
                        + "\n");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            for (int i = 0; i < ListePassager.size(); i++) {
                fichierPassager.writeBytes(ecrirePassager(ListePassager.get(i))
                        + "\n");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // Serialisation binaire
        //
        try {
            FileOutputStream fos = new FileOutputStream(BIN_LISTE_TRANSPORT);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            try {
                oos.writeObject(ListeTransport);
                oos.flush();
            } finally {
                try {
                    oos.close();
                } finally {
                    fos.close();
                }
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        try {
            FileOutputStream fos = new FileOutputStream(BIN_LISTE_TRAJET);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            try {
                oos.writeObject(ListeTrajet);
                oos.flush();
            } finally {
                try {
                    oos.close();
                } finally {
                    fos.close();
                }
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }

        try {
            FileOutputStream fos = new FileOutputStream(BIN_LISTE_PASSAGER);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            try {
                oos.writeObject(ListePassager);
                oos.flush();
            } finally {
                try {
                    oos.close();
                } finally {
                    fos.close();
                }
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /**
     * Recupere tout les transports contenue dans le fichier et les rend sous
     * forme de liste
     * 
     * @param
     * @return ArrayList<Transport>
     */
    public ArrayList<Transport> fillOutListeTransport() {
        // methode pour recuperer une liste de transport contenue dans un
        // fichier
        ArrayList<Transport> ListeTransport = new ArrayList<Transport>();
        String ligneFichier;
        String[] params;
        Transport temp;
        try {
            while ((ligneFichier = fichierTransport.readLine()) != null) {
                // temps que l'on peut lire une ligne dans le fichier on
                // recupere cette ligne on la decoupe par
                // rapport au CAR_SPACE et on l'enregistre dans un tableau
                params = ligneFichier.split(CAR_SPACE);
                // on creer un transport avec les information receuilli
                temp = new Transport(TypeTransport.toTypeTransport(params[0]),
                        Integer.parseInt(params[1]), Integer
                                .parseInt(params[2]));
                // que l'on ajoutera dans la liste des transport
                ListeTransport.add(temp);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return ListeTransport;
    }

    /**
     * Recupere tout les passagers contenue dans le fichier et les rend sous
     * forme de liste
     * 
     * @param
     * @return ArrayList<Transport>
     */
    public ArrayList<Passager> fillOutListePassager() {
        ArrayList<Passager> res = new ArrayList<Passager>();
        try {
            FileInputStream fis = new FileInputStream(BIN_LISTE_PASSAGER);
            ObjectInputStream ois = new ObjectInputStream(fis);
            try {
                res = (ArrayList<Passager>) ois.readObject();
            } finally {
                try {
                    ois.close();
                } finally {
                    fis.close();
                }
            }
        } catch (IOException ioe) {
            System.out.println(ioe.getMessage());
        } catch (ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
        }
        return res;
    }

    /**
     * Recupere tout les trajets contenue dans le fichier et les rend sous forme
     * de liste
     * 
     * @param
     * @return ArrayList<Trajet>
     */
    public ArrayList<Trajet> fillOutListeTrajet() {
        // methode pour recuperer une liste de transport contenue dans un
        // fichier
        ArrayList<Trajet> ListeTrajet = new ArrayList<Trajet>();
        String ligneFichier;
        String[] params;
        Trajet temp;
        try {
            while ((ligneFichier = fichierTrajet.readLine()) != null) {
                // temps que l'on peut lire une ligne dans le fichier on
                // recupere cette ligne on la decoupe par
                // rapport au CAR_SPACE et on l'enregistre dans un tableau
                params = ligneFichier.split(CAR_SPACE);
                // on creer un transport avec les informations receuillies
                temp = new Trajet(Ville.toVille(params[0]), Ville
                        .toVille(params[1]), stringToDate(params[2]),
                        stringToDate(params[3]), new Transport(TypeTransport
                                .valueOf(params[5]), Integer
                                .parseInt(params[6]), Integer
                                .parseInt(params[7])), Double
                                .parseDouble(params[4]));
                // que l'on ajoutera dans la liste des transport
                ListeTrajet.add(temp);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return ListeTrajet;
    }

    /**
     * Recupere toute les reservations contenue dans le fichier et les rend sous
     * forme de liste
     * 
     * @param
     * @return ArrayList<Reservation>
     */
    public ArrayList<Reservation> fillOutListeReservation() {
        // methode pour recuperer une liste de transport contenue dans un
        // fichier
        ArrayList<Reservation> listeReservation = new ArrayList<Reservation>();
        String ligneFichier;
        String[] params;
        Reservation temp;
        try {
            while ((ligneFichier = fichierTrajet.readLine()) != null) {
                // temps que l'on peut lire une ligne dans le fichier on
                // recupere cette ligne on la decoupe par
                // rapport au CAR_SPACE et on l'enregistre dans un tableau
                params = ligneFichier.split(CAR_SPACE);
                // on creer un transport avec les information receuilli
                temp = new Reservation(new Trajet(Ville.toVille(params[0]),
                        Ville.toVille(params[1]), new GregorianCalendar(Integer
                                .parseInt(params[2]), Integer
                                .parseInt(params[3]), Integer
                                .parseInt(params[4]), Integer
                                .parseInt(params[5]), Integer
                                .parseInt(params[6])), new GregorianCalendar(
                                Integer.parseInt(params[7]), Integer
                                        .parseInt(params[8]), Integer
                                        .parseInt(params[9]), Integer
                                        .parseInt(params[10]), Integer
                                        .parseInt(params[11])), new Transport(
                                TypeTransport.valueOf(params[12]), Integer
                                        .parseInt(params[13]), Integer
                                        .parseInt(params[14])), Double
                                .parseDouble(params[15])), Integer
                        .parseInt(params[16]));
                // que l'on ajoutera dans la liste des transport
                listeReservation.add(temp);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return listeReservation;
    }

    public static GregorianCalendar stringToDate(String sDate) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy-HH:mm");
        GregorianCalendar gc = new GregorianCalendar();
        try {
            gc.setTime((Date) sdf.parse(sDate));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return gc;
    }

    public static String getFormatedDate(Date date) {

        DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy-HH:mm");
        return dateFormat.format(date);
    }
}